package com.insurance.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.insurance.service.OrderService;
import com.insurance.service.ProposalCustomerService;
import com.insurance.service.ProposalService;
import com.insurance.service.dao.BidSubjectDao;
import com.insurance.service.entity.BidSubjectEntity;
import com.insurance.service.enums.BidSubjectStateEnum;
import com.insurance.service.service.BidSubjectService;
import com.insurance.common.constant.ConstantFlag;
import com.insurance.common.dto.BidSubjectEntityDto;
import com.insurance.common.exception.InsuranceException;
import com.insurance.common.utils.Query;
import com.insurance.entity.OrderEntity;
import com.insurance.entity.ProposalCustomerEntity;
import com.insurance.entity.ProposalEntity;
import com.insurance.enums.OrderStateEnum;
import com.insurance.enums.ProposalStatusEnum;
import com.insurance.pingan.bid.dto.accept.AcceptForFeeRequest;
import com.insurance.pingan.bid.dto.apply.BidApplyRequestDto;
import com.insurance.pingan.bid.dto.pay.PayRequestDto;
import com.insurance.pingan.bid.service.PingAnBidService;
import com.insurance.pingan.bid.utils.PingAnBidRequestUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import com.insurance.common.utils.PageUtils;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 投标service实现类
 */
@Slf4j
@Service("bidSubjectService")
public class BidSubjectServiceImpl extends ServiceImpl<BidSubjectDao, BidSubjectEntity> implements BidSubjectService {

    /**
     * 投保单service
     */
    @Autowired
    private ProposalService proposalService;

    /**
     * 订单service
     */
    @Autowired
    private OrderService orderService;

    /**
     * 投被保险人service
     */
    @Autowired
    private ProposalCustomerService proposalCustomerService;

    /**
     * 平安投保service
     */
    @Autowired
    private PingAnBidService pingAnBidService;

    //region 分页查询投标信息

    /**
     * 分页查询投标信息
     *
     * @param params 查询条件
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<BidSubjectEntity> page = this.page(
                new Query<BidSubjectEntity>().getPage(params),
                new QueryWrapper<BidSubjectEntity>()
        );

        return new PageUtils(page);
    }
    //endregion

    //region 保存投标信息和投被保险人信息

    /**
     * 保存投标信息和投被保险人信息
     *
     * @param bidSubjectEntity 投标对象
     * @param proposalEntity 投保单对象
     * @param customerList 投被保险人对象
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {InsuranceException.class, RuntimeException.class, Exception.class})
    @Override
    public boolean saveSubjectAndCustomers(BidSubjectEntity bidSubjectEntity, ProposalEntity proposalEntity,
                                    List<ProposalCustomerEntity> customerList) throws Exception{
        //保存投保单信息
        boolean proposalFlag = proposalService.save(proposalEntity);
        if(!proposalFlag){
            log.error("【保存投保单信息失败, 数据库保存异常】");
            throw new InsuranceException("保存投保单信息失败, 数据库保存异常");
        }
        //保存投标信息
        bidSubjectEntity.setProposalId(proposalEntity.getProposalId());
        boolean saveSubjectFlag = this.save(bidSubjectEntity);
        if(!saveSubjectFlag){
            log.error("【保存投标信息失败, 数据库保存异常】");
            throw new InsuranceException("保存投标信息失败, 数据库保存异常");
        }
        //保存投被保险人信息
        for(ProposalCustomerEntity proposalCustomerEntity : customerList){
            proposalCustomerEntity.setProposalId(proposalEntity.getProposalId());
        }
        boolean saveCustomerFlag = proposalCustomerService.saveBatch(customerList);
        if(!saveCustomerFlag){
            throw new InsuranceException("保存投被保险人信息失败, 数据库保存异常");
        }
        log.info("【保存投标信息成功】");
        //组装平安投保对象
        BidSubjectEntityDto bidSubjectEntityDto = new BidSubjectEntityDto();
        BeanUtils.copyProperties(bidSubjectEntity, bidSubjectEntityDto);
        BidApplyRequestDto bidApplyRequestDto = PingAnBidRequestUtil.convertPingAnApplyRequestData(bidSubjectEntityDto, customerList);
        //转换成平安json请求报文
        String requestBody = JSONObject.fromObject(bidApplyRequestDto).toString();
        log.info("【平安投保请求报文：{}】", requestBody);
        String result = pingAnBidService.applyForFee(requestBody);
        log.info("【平安投保响应报文：{}】", result);
        JSONObject formateResultJson = PingAnBidRequestUtil.pingAnApplyResultValidate(result);
        //成功
        if(!ConstantFlag.SUCCESS.equals(formateResultJson.getString(ConstantFlag.CODE))){
            log.error("【投标信息保存成功, 平安投保失败】");
            throw new InsuranceException("投标信息保存成功, 平安投保失败");
        }
        BidSubjectEntity updateBidSubjectEntity = new BidSubjectEntity();
        updateBidSubjectEntity.setSubjectId(bidSubjectEntity.getSubjectId());
        updateBidSubjectEntity.setApplyPolicyNo(formateResultJson.getString("applyPolicyNo"));
        updateBidSubjectEntity.setPolicyNo(formateResultJson.getString("policyNo"));
        updateBidSubjectEntity.setNoticeNo(formateResultJson.getString("noticeNo"));
        updateBidSubjectEntity.setTotalInsuredAmount(formateResultJson.getString("totalInsuredAmount"));
        updateBidSubjectEntity.setAmountCurrencyCode(formateResultJson.getString("amountCurrencyCode"));
        updateBidSubjectEntity.setTotalActualPremium(formateResultJson.getString("totalActualPremium"));
        updateBidSubjectEntity.setPremiumCurrencyCode(formateResultJson.getString("premiumCurrencyCode"));
        updateBidSubjectEntity.setInsuranceBeginDate(formateResultJson.getString("insuranceBeginDate"));
        updateBidSubjectEntity.setInsuranceEndDate(formateResultJson.getString("insuranceEndDate"));
        updateBidSubjectEntity.setProductName(formateResultJson.getString("productName"));
        updateBidSubjectEntity.setUpdateTime(new Date());
        updateBidSubjectEntity.setState("1");
        boolean updateFlag = this.updateById(updateBidSubjectEntity);
        if(!updateFlag){
            log.error("【投标信息保存成功, 平安投保成功, 修改投标信息失败】");
//            throw new InsuranceException("投标信息保存成功, 平安投保成功, 修改投标信息失败");
        }
        ProposalEntity proposal = proposalService.getById(bidSubjectEntity.getProposalId());
        proposal.setStartDate(updateBidSubjectEntity.getInsuranceBeginDate());
        proposal.setEndDate(updateBidSubjectEntity.getInsuranceEndDate());
        boolean updateProposalFlag = proposalService.updateById(proposal);
        if(!updateProposalFlag){
            log.error("【投标信息保存成功, 平安投保成功, 修改投保单信息失败】");
        }
        return true;
    }
    //endregion

    //region 通过投保单主键查询

    /**
     * 通过投保单主键查询
     *
     * @param proposalId 投保单主键
     * @return
     */
    @Override
    public BidSubjectEntity getByProposalId(String proposalId){
        QueryWrapper<BidSubjectEntity> queryWrapper = new QueryWrapper<BidSubjectEntity>();
        queryWrapper.eq("proposal_id", proposalId);
        return this.getOne(queryWrapper);
    }
    //endregion

    //region 平安投标预支付订单

    /**
     * 平安投标预支付订单
     *
     * @param subjectId
     * @param orderEntity
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {InsuranceException.class, RuntimeException.class, Exception.class})
    @Override
    public JSONObject prePayFinance(String callUrl, String subjectId, OrderEntity orderEntity){
        BidSubjectEntity bidSubjectEntity = this.getById(subjectId);
        ProposalEntity proposalEntity = proposalService.getById(bidSubjectEntity.getProposalId());
        List<ProposalCustomerEntity> customerEntityList = proposalCustomerService.findByProposalId(bidSubjectEntity.getProposalId());
        BidSubjectEntityDto bidSubjectEntityDto = new BidSubjectEntityDto();
        BeanUtils.copyProperties(bidSubjectEntity, bidSubjectEntityDto);
        //组装平安
        PayRequestDto payRequestDto = PingAnBidRequestUtil.createPayRequestDto(callUrl, proposalEntity, customerEntityList.get(0), bidSubjectEntityDto);
        String payRequestBody = JSONObject.fromObject(payRequestDto).toString();
        orderEntity.setTransactionId(payRequestDto.getTradeNo());
        orderEntity.setSign(payRequestDto.getSignMsg());
        boolean orderFlag = orderService.save(orderEntity);
        if(!orderFlag){
            log.error("【投标预支付订单下单失败, 订单保存失败】");
            throw new InsuranceException("投标预支付订单下单失败, 订单保存失败");
        }
        bidSubjectEntity.setOrderId(orderEntity.getOrderId());
        boolean subjectFlag = this.updateById(bidSubjectEntity);
        if(!subjectFlag){
            log.error("【投标预支付订单下单失败, 修改投标信息失败】");
            throw new InsuranceException("投标预支付订单下单失败, 修改投标信息失败");
        }

        String result = pingAnBidService.prePayFinance(payRequestBody);
        JSONObject formatePayResultJson = PingAnBidRequestUtil.pingAnPrePayFinanceResultValidate(result);
        if(!ConstantFlag.SUCCESS.equals(formatePayResultJson.getString(ConstantFlag.CODE))){
            log.error("【投标信息保存成功, 平安预支付接口失败】");
            throw new InsuranceException("投标信息保存成功, 平安预支付接口失败");
        }
        log.info("【投标信息保存成功, 平安预支付接口成功】");
        log.info(formatePayResultJson.toString());
        return formatePayResultJson;
    }
    //endregion

    /**
     * 查询投保单
     *
     * {
     * "ret": "0",
     * "msg": "",
     * "requestId": "acceptForFee123456789",
     * "data":{
     * "result":{
     * "applyPolicyNo": "51077003900230858285",
     * "policyNo": "11077003900162941991",
     * "noticeNo": "",
     * "totalInsuredAmount": "1000.00",
     * "amountCurrencyCode": "01",
     * "totalActualPremium": "500.00",
     * "premiumCurrencyCode": "01",
     * "insuranceBeginDate": "2020-09-28 00:00:00",
     * "insuranceEndDate": "2021-09-22 23:59:59",
     * "policyUrl": "",
     * "invoiceUrl": ""
     * },
     * "responseCode": "888888",
     * "responseMsg": "该投保单已承保"
     * }
     * }
     *
     * @param subjectId
     * @return
     */
    @Override
    public JSONObject acceptForFee(String subjectId){
        BidSubjectEntity bidSubjectEntity = this.getById(subjectId);
        OrderEntity orderEntity = orderService.getById(bidSubjectEntity.getOrderId());
        AcceptForFeeRequest acceptForFeeRequest = PingAnBidRequestUtil.createAcceptForFeeRequest(bidSubjectEntity.getApplyPolicyNo(), orderEntity.getTransactionId());
        String acceptRequestJsonStr = JSONObject.fromObject(acceptForFeeRequest).toString();
        log.info("【平安主动查询投保信息, 请求报文：{}】", acceptRequestJsonStr);
        String result = pingAnBidService.acceptForFee(acceptRequestJsonStr);
        log.info("【平安主动查询投保信息, 响应报文：{}】", result);
        JSONObject jsonObject = PingAnBidRequestUtil.acceptForFeeValidate(result);
        if(!ConstantFlag.SUCCESS.equals(jsonObject.getString(ConstantFlag.CODE))){
            log.error("【平安主动查询接口查询失败】");
            throw new InsuranceException("平安主动查询接口查询失败");
        }
        orderEntity.setOrderState(OrderStateEnum.COMPLETE.getCode());
        orderEntity.setUpdateTime(new Date());
        bidSubjectEntity.setState(BidSubjectStateEnum.IS_COMPLETE.getCode());
        bidSubjectEntity.setPolicyNo(jsonObject.containsKey("policyNo") ? jsonObject.getString("policyNo") : "");
        ProposalEntity proposalEntity = proposalService.getById(bidSubjectEntity.getProposalId());
        proposalEntity.setInsuranceNo(jsonObject.containsKey("policyNo") ? jsonObject.getString("policyNo") : "");
        proposalEntity.setStartDate(jsonObject.containsKey("insuranceBeginDate") ? jsonObject.getString("insuranceBeginDate") : "");
        proposalEntity.setEndDate(jsonObject.containsKey("insuranceEndDate") ? jsonObject.getString("insuranceEndDate") : "");
        proposalEntity.setUpdateTime(new Date());
        proposalEntity.setState(ProposalStatusEnum.ISINSURE.getCode());
        boolean subjectFlag = this.updateById(bidSubjectEntity);
        if(!subjectFlag){
            log.error("【平安主动查询接口, 查询成功, 修改投标信息状态失败】");
            throw new InsuranceException("平安主动查询接口, 查询成功, 修改投标信息状态失败");
        }
        boolean orderFlag = orderService.updateById(orderEntity);
        if(!orderFlag){
            log.error("【平安主动查询接口, 查询成功, 修改订单状态失败】");
            throw new InsuranceException("平安主动查询接口, 查询成功, 修改订单状态失败");
        }
        boolean proposalFlag = proposalService.updateById(proposalEntity);
        if(!proposalFlag){
            log.error("【平安主动查询接口, 查询成功, 修改投保单状态失败】");
            throw new InsuranceException("平安主动查询接口, 查询成功, 修改投保单状态失败");
        }
        log.info("【平安主动查询接口, 查询成功, subjectId：{}】", subjectId);
        return jsonObject;
    }

}